package org.folio.rest.impl;

import cn.hutool.core.collection.CollUtil;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.pojo.AppraisalExportObject;
import org.folio.rest.impl.util.DBName;
import org.folio.rest.impl.util.FileExport;
import org.folio.rest.impl.util.ParallelAsync;
import org.folio.rest.impl.util.ParallelResult;
import org.folio.rest.jaxrs.model.Appraisal;
import org.folio.rest.jaxrs.model.AppraisalCollection;
import org.folio.rest.jaxrs.model.AppraisalGroup;
import org.folio.rest.jaxrs.model.Errors;
import org.folio.rest.jaxrs.resource.PartyAppraisal;
import org.folio.rest.persist.PgUtil;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.persist.cql.CQLWrapper;
import org.folio.rest.tools.messages.Messages;
import org.folio.rest.tools.utils.ValidationHelper;

import javax.ws.rs.core.Response;
import java.util.*;

import static io.vertx.core.Future.succeededFuture;

/**
 * @author lee
 * @Classname PartyAppraisal
 * @Description TODO
 * @Date 2020/9/15 18:22
 * @Created by lee
 */
public class PartyAppraisalImpl implements PartyAppraisal {
    private final Logger logger = LoggerFactory.getLogger("modparty");
    private final Messages messages = Messages.getInstance();
    private static final String NOTIFY_TABLE = "party_appraisal";

    @Override
    public void postPartyAppraisal(String lang, Appraisal entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        if (!"1".equals(entity.getState()) && !"0".equals(entity.getState()) && !"2".equals(entity.getState())) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("state", entity.getState(),
                    "审核的状态值不在取值范围内!");
            asyncResultHandler.handle(Future.succeededFuture(PostPartyAppraisalResponse.respond500WithTextPlain(valErr)));
            return;
        }
        if (entity.getIdList() == null || entity.getIdList().size() == 0) {
            Errors valErr = ValidationHelper.createValidationErrorMessage("idList", "NULL",
                    "要审核的评论不能是空");
            asyncResultHandler.handle(Future.succeededFuture(PostPartyAppraisalResponse.respond500WithTextPlain(valErr)));
            return;
        }
        PostgresClient pgUtil = PgUtil.postgresClient(vertxContext, okapiHeaders);
        pgUtil.getById(NOTIFY_TABLE, new JsonArray(entity.getIdList()), Appraisal.class, reply -> {
            if (reply.succeeded()) {
                Map<String, Appraisal> result = reply.result();
                Iterator<Map.Entry<String, Appraisal>> it = result.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<String, Appraisal> tmp = it.next();
                    Appraisal appraisal = tmp.getValue();
                    appraisal.setState(entity.getState());
                    appraisal.setRemark(entity.getRemark());
                    appraisal.setChecker(entity.getChecker());
                    pgUtil.update(NOTIFY_TABLE, appraisal, appraisal.getId(), update -> {

                    });

                }
                asyncResultHandler.handle(Future.succeededFuture(PostPartyAppraisalResponse.respond201WithApplicationJson(entity, PostPartyAppraisalResponse.headersFor201())));
                return;
            } else {
                Errors valErr = ValidationHelper.createValidationErrorMessage("idList", "NULL",
                        "要审核的评论不能是空");
                asyncResultHandler.handle(Future.succeededFuture(PostPartyAppraisalResponse.respond500WithTextPlain(valErr)));
                return;
            }
        });
        asyncResultHandler.handle(Future.succeededFuture(PostPartyAppraisalResponse.respond201WithApplicationJson(entity, PostPartyAppraisalResponse.headersFor201())));
    }


    @Override
    public void getPartyAppraisal(String query, int offset, int limit, String lang, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        CQLWrapper cql = null;
        try {
            // 将查询条件语句转换成适合数据库查询的CQL 语句，并返回 CQL 对象
            cql = PartyUtil.getCQL(query, limit, offset, NOTIFY_TABLE);

        } catch (Exception e) {
            //查询条件转换可能出现的异常处理
            ValidationHelper.handleError(e, asyncResultHandler);
            return;
        }
        //初始化数据库连接，并调用其中的 Get 方法 异步进行查询操作
        PgUtil.postgresClient(vertxContext, okapiHeaders)
                .get(NOTIFY_TABLE, org.folio.rest.jaxrs.model.AppraisalGroup.class, new String[]{"*"}, cql,
                        true, false,
                        reply -> {
                            if (reply.succeeded()) {
                                //将查询结果存放到使用RMB框架构建生成的对象中
                                AppraisalCollection notes = new AppraisalCollection();
                                List<AppraisalGroup> AppraisalGroupList
                                        = reply.result().getResults();
                                notes.setAppraisalGroup(AppraisalGroupList);
                                Integer totalRecords = reply.result().getResultInfo().getTotalRecords();
                                notes.setTotalRecords(totalRecords);
                                //异步通知调用方，同样使用标准化构建的对象方法进行通知
                                asyncResultHandler.handle(Future.succeededFuture(
                                        GetPartyAppraisalResponse.respond200WithApplicationJson(notes)));
                            } else {
                                ValidationHelper.handleError(reply.cause(), asyncResultHandler);
                            }
                        });
    }

    @Override
    public void getPartyAppraisalExportExcel(String query, int offset, int limit, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
        CQLWrapper cqlWrapper = null;
        try {
            cqlWrapper = PartyUtil.getCQL(query,-1,-1, DBName.NOTIFY_TABLE_PARTY_APPRAISAL);
        }catch (Exception e){
            Errors valErr = ValidationHelper.createValidationErrorMessage("query", query,
                    "Your request query is empty, this is not allowed  ");
            asyncResultHandler.handle(succeededFuture(GetPartyAppraisalResponse.respond422WithApplicationJson(valErr)));
            return;
        }
        HashMap<String, String> mapping = CollUtil.newHashMap();

        mapping.put("appraisal", "评价内容");
        mapping.put("score", "评星");
        mapping.put("state", "审核状态");
        mapping.put("createDate","评价时间");
        mapping.put("barcode", "评价人账号");
        mapping.put("readerName", "读者名称");
        mapping.put("checker", "评价人名称");

        PgUtil.postgresClient(vertxContext, okapiHeaders).get(
                DBName.NOTIFY_TABLE_PARTY_APPRAISAL,AppraisalGroup.class,new String[]{"*"},
                cqlWrapper,true,false,
                reply->{
                   if (reply.succeeded()){
                       List<AppraisalGroup> list = reply.result().getResults();
                       List<AppraisalExportObject> exportObjectList = new ArrayList<>();
                       list.forEach(a->{
                           AppraisalExportObject temp = new AppraisalExportObject();
                           temp.setAppraisal(a.getAppraisal());
                           temp.setCreateDate(a.getCreateDate());
                           temp.setChecker(a.getChecker());
                           temp.setScore(a.getScore());
                           temp.setState(a.getState());
                           if (a.getReaderReserveGroup().size()>0){
                              temp.setReaderName( a.getReaderReserveGroup().get(0).getName());
                              temp.setBarcode(a.getReaderReserveGroup().get(0).getBarcode());
                           }
                           exportObjectList.add(temp);
                       });
                       FileExport.fileExports(mapping, exportObjectList, h -> {
                            if (h.succeeded()){
                                asyncResultHandler.handle(succeededFuture(GetPartyAppraisalExportExcelResponse.respond200WithApplicationOctetStream(h.result())));
                                return;
                            }else {
                                ValidationHelper.handleError(reply.cause(), asyncResultHandler);
                                return;
                            }
                       });
                   }
                    ValidationHelper.handleError(reply.cause(), asyncResultHandler);
                    return;
                }
        );
    }

    @Override
    public void postPartyAppraisalBatchDel(String lang, Appraisal entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
            if (entity.getIdList() == null || entity.getIdList().size() ==0){
                Errors valErr = ValidationHelper.createValidationErrorMessage("id", "0",
                        " 请至少选择一条评论  ");
                asyncResultHandler.handle(succeededFuture(GetPartyAppraisalResponse.respond422WithApplicationJson(valErr)));
                return;
            }
        PostgresClient pg = PgUtil.postgresClient(vertxContext, okapiHeaders);
        ParallelAsync executor = new ParallelAsync();
        entity.getIdList().forEach(a->{
            executor.addAsyncTask(batchAppraisal(pg,a));
        });
        executor.start();
        executor.setHandler(reply->{

            asyncResultHandler.handle(succeededFuture(PostPartyAppraisalBatchDelResponse.respond201WithApplicationJson(entity,PostPartyAppraisalBatchDelResponse.headersFor201())));
        });
    }

    private Future<ParallelResult> batchAppraisal(PostgresClient pg ,String id){
        Future<ParallelResult> future = Future.future();
        pg.delete(DBName.NOTIFY_TABLE_PARTY_APPRAISAL,id,reply->{
            ParallelResult result = new ParallelResult();
            result.setFlag(true);

            if (reply.failed()){
              result.setFlag(false);
            }
            future.complete(result);
        });
        return future;
    }


}
